package simtester.cloud

import com.amazonaws.AmazonServiceException
import com.amazonaws.services.ec2.model.DescribeInstancesRequest

class CloudInstance {
    def id
    def publicDnsName
    def publicIpAddress
    def state
    def amiId
    def type
    def test

    private Cloud cloud
    private key

    CloudInstance(args) {
        cloud           = args.cloud
        id              = args.id
        publicDnsName   = args.publicDnsName
        publicIpAddress = args.publicIpAddress
        state           = args.state
        amiId           = args.amiId
        type            = args.type
        test            = args.test ?: false
        key             = args.key
    }
    
    void sendFile(opts, file) {
        updateUntil { publicDnsName }
        ssh().upload(file, to: opts.to)
    }
    
    boolean fileExists(filename) {
        updateUntil { publicDnsName }
        def output = ssh().exec("ls ${filename}")
        
        return output == filename ? true : false
    }
    
    def getState() {
        updateInfo()
        return state
    }
    
    def viewText(filename) {
        updateUntil { publicDnsName }

        return ssh().exec("cat $filename")
    }
    
    def exec(cmd) {
        updateUntil { publicDnsName }

        return ssh().exec(cmd)
    }
    
    void execAsync(cmd) {
        updateUntil { publicDnsName }

        ssh().execAsync(cmd)
    }
    
    
    private void updateInfo() {
        try {
            def request = new DescribeInstancesRequest()
            request.instanceIds = [id]
            
            def searchResults = cloud.ec2.describeInstances(request)
            def instance = searchResults.reservations[0].instances[0]
            
            //TODO: May want to take care of the case where the search fails
            if (instance.instanceId) {
                cloud = this.cloud
                publicDnsName = instance.publicDnsName
                publicIpAddress = instance.publicIpAddress
                state = instance.state.name
            }
            
        } catch (AmazonServiceException ase) {
            if (ase.errorCode == 'InvalidInstanceID.NotFound') {
                // Do nothing
            } else {
                throw new CloudException(ase.message)
            }
        }
    }
    
    private void updateUntil(Closure closure) {
        def mins = 4
        def timeout     = test ? 3 : (mins * 60000)
        def timeoutincr = test ? 1 :  3000
        
        try {
            Utils.waitFor(limit: timeout, step: timeoutincr) {
                if (closure.call()) {
                    return true
                }
                updateInfo()
            }
        } catch (TimeoutException e) {
            throw new CloudException("Instance not ready to be used after waiting for $mins minutes")
        }
    }
    
    private def ssh() {
        return new CloudInstanceSSH(address: publicDnsName, user: 'ec2-user', authkey: key)
    }

}